/*
 * Copyright 2010 Christoph Widulle (christoph.widulle@googlemail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */



package com.android1.amarena2d.nodes.behavior.delegates;

import com.android1.amarena2d.commons.collections.FixedSizeArray;
import com.android1.amarena2d.nodes.behavior.Syncable;
import com.badlogic.gdx.math.Vector2;

//todo maybe too oversized
public class SyncDelegateImpl implements SyncDelegate, SyncDelegateInternal {

    protected Syncable owner;
    protected Syncable masterPos;
    protected Syncable masterSize;
    protected final FixedSizeArray<Syncable> posSyncListener = new FixedSizeArray<Syncable>(10);
    protected final FixedSizeArray<Syncable> sizeSyncListener = new FixedSizeArray<Syncable>(10);
    protected float posSyncScale = 1F;
    protected Vector2 scaleSave;

    public SyncDelegateImpl(Syncable owner) {
        this.owner = owner;
    }

    public void firePosUpdate(final float x, final float y) {
        final int size = posSyncListener.size();
        if (size > 0) {
            for (int i = 0; i < size; i++) {
                posSyncListener.get(i).sync().internal().onSyncPos(x, y);
            }
        }
    }

    public void fireSizeUpdate(final float w, final float h) {
        final int size = sizeSyncListener.size();
        if (size > 0) {
            for (int i = 0; i < size; i++) {
                posSyncListener.get(i).sync().internal().onSyncSize(w, h);
            }
        }
    }

    /**
     * @param scale
     */
    public void setPosSyncScale(final float scale) {
        if (scaleSave == null)
            scaleSave = new Vector2(masterPos.getX(), masterPos.getY());
        this.posSyncScale = scale;
    }

    @Override
    public void syncPositionFrom(Syncable syncable) {
        if (this.masterPos != null) {
            this.masterPos.sync().internal().unregisterPositionSyncListener(owner);
        }
        this.masterPos = syncable;
        this.masterPos.sync().internal().registerPositionSyncListener(owner);

    }

    @Override
    public void syncSizeFrom(Syncable syncable) {
        if (this.masterSize != null) {
            this.masterSize.sync().internal().unregisterSizeSyncListener(owner);
        }
        this.masterSize = syncable;
        this.masterSize.sync().internal().registerSizeSyncListener(owner);
    }

    @Override
    public void revokePositionSync() {
        if (this.masterPos != null) {
            this.masterPos.sync().internal().unregisterPositionSyncListener(owner);
            this.masterPos = null;
        }
    }

    @Override
    public void revokeSizeSync() {
        if (this.masterSize != null) {
            this.masterSize.sync().internal().unregisterSizeSyncListener(owner);
            this.masterSize = null;
        }
    }

    @Override
    public void registerPositionSyncListener(Syncable hasXY) {
        if (!posSyncListener.contains(hasXY, true))
            posSyncListener.add(hasXY);
    }

    @Override
    public void registerSizeSyncListener(Syncable hasSize) {
        if (!sizeSyncListener.contains(hasSize, true))
            sizeSyncListener.add(hasSize);
    }

    @Override
    public void unregisterPositionSyncListener(Syncable hasXY) {
        posSyncListener.remove(hasXY);
    }

    @Override
    public void unregisterSizeSyncListener(Syncable hasSize) {
        sizeSyncListener.remove(hasSize);
    }

    @Override
    public boolean hasSyncSizeListener() {
        return sizeSyncListener.size() > 0;
    }

    @Override
    public boolean hasSyncPositionListener() {
        return posSyncListener.size() > 0;
    }

    @Override
    public void onSyncPos(float x, float y) {
        if (scaleSave != null) {
            final float x2 = (x - scaleSave.x) * posSyncScale;
            final float y2 = (y - scaleSave.y) * posSyncScale;
            scaleSave.x = x;
            scaleSave.y = y;
            owner.addXY(x2, y2);
        } else
            owner.setXY(x, y);

    }

    @Override
    public void onSyncSize(float w, float h) {
        owner.setSize(w, h);
    }

    @Override
    public SyncDelegateInternal internal() {
        return this;
    }
}

